home *** CD-ROM | disk | FTP | other *** search
/ Aminet 15 / Aminet 15 - Nov 1996.iso / Aminet / dev / c / EasygadgetsSou.lha / EasyGadgets / Listview_kind.c < prev    next >
C/C++ Source or Header  |  1994-11-18  |  25KB  |  851 lines

  1. /*
  2.  *    File:                    Listview_kind.c
  3.  *    Description:    BOOPSI listview gadget class
  4.  *
  5.  *    (C) 1994, Ketil Hunn
  6.  *
  7.  */
  8.  
  9. #ifndef LISTVIEW_KIND_C
  10. #define LISTVIEW_KIND_C
  11.  
  12. /* Make sure everything is added from PopUpMenuClass.h */
  13. #define POPUPMENUCLASS_PRIVATE  1
  14.  
  15. #include    "Listview_kind.h"
  16. #include    <string.h>
  17. #include    <math.h>
  18.  
  19. #define    DisposeListviewClass(class)    FreeClass(class);
  20.  
  21. static ULONG __saveds __asm EGLV_Dispatcher(register __a0 Class *class,
  22.                                                                                         register __a2 Object *object,
  23.                                                                                         register __a1 Msg msg);
  24. static ULONG EGLV_NEW(Class *class, Object *object, struct opSet *ops);
  25. static ULONG EGLV_DISPOSE(Class *class, Object *object, Msg msg);
  26. static ULONG EGLV_SET(Class *class, Object *object, struct opSet *ops);
  27. static ULONG EGLV_GET(Class *class, Object *object, struct opGet *opg);
  28. static ULONG EGLV_UPDATE(Class *class, Object *object, struct opUpdate *opu);
  29. static ULONG EGLV_NOTIFY(Class *class, Object *object, struct opUpdate *opu);
  30. static ULONG EGLV_RENDER(Class *class, Object *object, struct gpRender *gpr);
  31. static ULONG EGLV_GOACTIVE(Class *class, Object *object, struct gpInput *gpi);
  32. static ULONG EGLV_HANDLEINPUT(Class *class, Object *object, struct gpInput *gpi);
  33. static ULONG EGLV_GOINACTIVE(Class *class, Object *object, struct gpGoInactive *gpgi);
  34.  
  35. /* Protos for static help functions. */
  36.  
  37. static void     EGLV_MakeCheckings( struct ListviewData *PD );
  38.  
  39. static void     EGLV_GetGadgetRect( Object *object,
  40.                                     struct GadgetInfo *gi,
  41.                                     struct Rectangle *rect );
  42.  
  43. static void     EGLV_DrawPopupWindow( struct ListviewData *PD,
  44.                                       struct DrawInfo *dri,
  45.                                       ULONG From,
  46.                                       LONG Count );
  47.  
  48. static void     EGLV_DrawFrame( struct Window *win,
  49.                                 int order,
  50.                                 struct DrawInfo *dri,
  51.                                 UBYTE *name,
  52.                                 struct TextFont *tf,
  53.                                 BOOL Active,
  54.                                 BOOL NewLook,
  55.                                 ULONG ItemHeight );
  56.  
  57.  
  58. /*******************************************************************/
  59. /*******************************************************************/
  60. /* The real code starts here.                                      */
  61. /*******************************************************************/
  62. /*******************************************************************/
  63.  
  64. Class *CreateListviewClass()
  65. {
  66.     Class *class;
  67.  
  68.     class=MakeClass(NULL, GADGETCLASS, NULL, sizeof(struct ListviewData), 0);
  69.     if(class)
  70.         class->cl_Dispatcher.h_Entry=(HookFunction)EGLV_Dispatcher;
  71.  
  72.     return( class );
  73. }
  74.  
  75.  
  76. /*******************************************************************/
  77. /*******************************************************************/
  78. /* Listview specific class code.                                  */
  79. /*******************************************************************/
  80. /*******************************************************************/
  81.  
  82. static ULONG __saveds __asm EGLV_Dispatcher(register __a0 Class *class,
  83.                                                                                         register __a2 Object *object,
  84.                                                                                         register __a1 Msg msg)
  85. {
  86.     ULONG retval;
  87.  
  88.     switch(msg->MethodID)
  89.     {
  90.         case OM_NEW:
  91.             retval=EGLV_NEW(class, object, (struct opSet *)msg);
  92.             break;
  93.         case OM_DISPOSE:
  94.             retval=EGLV_DISPOSE(class, object, msg);
  95.             break;
  96.         case OM_SET:
  97.             retval=EGLV_SET(class, object, (struct opSet *)msg);
  98.             break;
  99.         case OM_GET:
  100.             retval=EGLV_GET(class, object, (struct opGet *)msg);
  101.             break;
  102.         case OM_UPDATE:
  103.             retval=EGLV_UPDATE(class, object, (struct opUpdate *)msg);
  104.             break;
  105.         case OM_NOTIFY:
  106.             retval=EGLV_NOTIFY(class, object, (struct opUpdate *)msg);
  107.             break;
  108.         case GM_RENDER:
  109.             retval = EGLV_RENDER(class, object, (struct gpRender *)msg);
  110.             break;
  111.         case GM_GOACTIVE:
  112.             retval=EGLV_GOACTIVE(class, object, (struct gpInput *)msg);
  113.             break;
  114.         case GM_HANDLEINPUT:
  115.             retval=EGLV_HANDLEINPUT(class, object, (struct gpInput *)msg);
  116.             break;
  117.         case GM_GOINACTIVE:
  118.             retval=EGLV_GOINACTIVE(class, object, (struct gpGoInactive *)msg);
  119.             break;
  120.         default:
  121.             retval=DoSuperMethodA(class, object, msg);
  122.             break;
  123.     }
  124.     return retval;
  125. }
  126.  
  127. static ULONG EGLV_NEW(Class *class, Object *object, struct opSet *ops)
  128. {
  129.     Object *object;
  130.     struct ListviewData *lv;
  131.  
  132.     object=(Object *)DoSuperMethodA(class, object, (Msg)ops);
  133.     if(object)
  134.     {
  135.         lv=INST_DATA(class, object);
  136.  
  137.         lv->Labels=(struct List *)GetTagData(EGLV_Labels, NULL, ops->ops_AttrList);
  138.         lv->Active=GetTagData(EGLV_Active, 0, ops->ops_AttrList);
  139.  
  140.         EGLV_MakeCheckings(lv);
  141.  
  142.         lv->Font=(struct TextFont *)GetTagData(EGLV_TextFont, NULL, ops->ops_AttrList);
  143.  
  144.         lv->FrameImage=(struct Image *)NewObject(NULL,"frameiclass",
  145.                                                                                             IA_Recessed,    FALSE,
  146.                                                                                             IA_EdgesOnly,    FALSE,
  147.                                                                                             IA_FrameType,    FRAME_BUTTON,
  148.                                                                                             TAG_END);
  149.         if(lv->FrameImage==NULL)
  150.         {
  151.             CoerceMethod(class, object, OM_DISPOSE);
  152.             object=NULL;
  153.         }
  154.     }
  155.     return (ULONG)object;
  156. }
  157.  
  158. static ULONG EGLV_DISPOSE(Class *class, Object *object, Msg msg )
  159. {
  160.     struct ListviewData *lv=INST_DATA(class, object);
  161.  
  162.     if(lv->popup_window)
  163.         CloseWindow(lv->popup_window);
  164.  
  165.     if(lv->FrameImage)
  166.         DisposeObject(lv->FrameImage);
  167.  
  168.     return DoSuperMethodA(class, object, msg);
  169. }
  170.  
  171. static ULONG EGLV_SET(Class *class, Object *object, struct opSet *ops)
  172. {
  173.     ULONG retval;
  174.     struct ListviewData *lv = INST_DATA( class, object );
  175.     struct TagItem *tag, notify;
  176.     UWORD old_active;
  177.  
  178.     retval=DoSuperMethodA(class, object, (Msg)ops);
  179.  
  180.     /* I decided that it would be best that the values which are
  181.     ** specific to this class, could bot be changed when we have
  182.     ** our Listview window opened. */
  183.     if((ops->ops_AttrList!=NULL) && (lv->popup_window==NULL))
  184.     {
  185.     if(tag=FindTagItem(EGLV_Labels, ops->ops_AttrList))
  186.         {
  187.             lv->Labels=(struct List *)tag->ti_Data;
  188.             retval=TRUE;
  189.         }
  190.  
  191.     old_active = lv->Active;
  192.     if(tag=FindTagItem(EGLV_Active, ops->ops_AttrList))
  193.         {
  194.             lv->Active=tag->ti_Data;
  195.             retval=TRUE;
  196.         }
  197.  
  198.         EGLV_MakeCheckings(lv);
  199.  
  200.         if(tag=FindTagItem(EGLV_TextFont, ops->ops_AttrList))
  201.         {
  202.             lv->Font=(struct TextFont *)tag->ti_Data;
  203.             retval=TRUE;
  204.         }
  205.  
  206.         if(old_active!=lv->Active)
  207.         {
  208.             /* We send ourselves a OM_NOTIFY message, which will
  209.             ** eventually be broadcasted as OM_UPDATE message
  210.             ** to the target object. Note that we don't send it
  211.             ** simply to our parent, but to ourselves, so if
  212.             ** we have a children which needs to add it's own
  213.             ** data it will be added. */
  214.             EGLV_SetTagArg( notify, TAG_END, NULL );
  215.             (VOID)DoMethod( object, OM_NOTIFY, ¬ify, ops->ops_GInfo, 0 );
  216.         }
  217.     }
  218.     return( retval );
  219. }
  220.  
  221. static ULONG EGLV_GET(Class *class, Object *object, struct opGet *opg)
  222. {
  223.     ULONG retval;
  224.     struct ListviewData *lv=INST_DATA(class, object);
  225.  
  226.     switch(opg->opg_AttrID)
  227.     {
  228.         case EGLV_Labels:
  229.             *opg->opg_Storage=(ULONG)lv->Labels;
  230.             retval=TRUE;
  231.             break;
  232.         case EGLV_Active:
  233.             *opg->opg_Storage = (ULONG)lv->Active;
  234.             retval = TRUE;
  235.             break;
  236.         case EGLV_TextFont:
  237.             *opg->opg_Storage=(ULONG)lv->Font;
  238.             retval=TRUE;
  239.             break;
  240.         default:
  241.             retval=DoSuperMethodA(class, object, (Msg)opg);
  242.             break;
  243.     }
  244.     return retval;
  245. }
  246.  
  247. static ULONG EGLV_UPDATE(Class *class, Object *object, struct opUpdate *opu)
  248. {
  249.     ULONG retval;
  250.     struct ListviewData *lv = INST_DATA( class, object );
  251.     struct TagItem *tag, notify;
  252.     struct RastPort *rp;
  253.  
  254.     retval=DoSuperMethodA(class, object, opu);
  255.  
  256.     /* Update only if gadget isn't currently manipulated. */
  257.     if(lv->popup_window==NULL)
  258.     {
  259.       if(opu->opu_AttrList)
  260.         {
  261.           if(tag=FindTagItem(EGLV_Active, opu->opu_AttrList))
  262.             {
  263.                 if(tag->ti_Data!=lv->Active)
  264.                 {
  265.                     lv->Active=tag->ti_Data;
  266.                     EGLV_MakeCheckings(lv);
  267.  
  268.                     if(rp=ObtainGIRPort(opu->opu_GInfo))
  269.                     {
  270.                         DoMethod(object, GM_RENDER, opu->opu_GInfo, rp, GREDRAW_UPDATE);
  271.                     ReleaseGIRPort(rp);
  272.                     }
  273.         
  274.                   /* Notify the change. */
  275.                   EGLV_SetTagArg( notify, TAG_END, NULL );
  276.                   (void)DoMethod(object, OM_NOTIFY, ¬ify, opu->opu_GInfo, 0);
  277.               }
  278.           }
  279.       }
  280.   }
  281.     return retval;
  282. }
  283.  
  284. static ULONG EGLV_NOTIFY(Class *class, Object *object, struct opUpdate *opu)
  285. {
  286.     struct TagItem tags[3];
  287.     struct ListviewData *lv=INST_DATA(class, object);
  288.  
  289.     EGLV_SetTagArg(tags[0], GA_ID, ((struct Gadget *)object)->GadgetID);
  290.     EGLV_SetTagArg(tags[1], EGLV_Active, lv->Active);
  291.  
  292.     /* If there are no previous tags in OM_NOTIFY message, we
  293.     ** add them there as only ones. Otherwise we tag previous
  294.     ** tags to the end of our tags. Got it? :')
  295.     */
  296.     if(opu->opu_AttrList==NULL)
  297.         EGLV_SetTagArg(tags[2], TAG_END, NULL);
  298.     else
  299.         EGLV_SetTagArg(tags[2], TAG_MORE, opu->opu_AttrList );
  300.  
  301.     return DoSuperMethod(class, object, OM_NOTIFY, tags, opu->opu_GInfo, opu->opu_Flags);
  302. }
  303.  
  304. static ULONG EGLV_RENDER(Class *class, Object *object, struct gpRender *gpr)
  305. {
  306.     ULONG retval, State;
  307.     struct Gadget *gad = (struct Gadget *)object;
  308.     struct Rectangle rect;
  309.     struct DrawInfo *dri;
  310.     struct IBox container;
  311.     struct Node *node;
  312.     struct TextExtent temp_te;
  313.     struct RastPort *RP = gpr->gpr_RPort;
  314.     UWORD BorderWidth, BorderHeight, TextWidth;
  315.     UWORD patterndata[2] = { 0x2222, 0x8888 };
  316.     ULONG TextPen, ImagePen1, ImagePen2;
  317.     struct ListviewData *lv = INST_DATA( class, object );
  318.  
  319.     retval=DoSuperMethodA(class, object, gpr);
  320.  
  321.     /* Get real Min and Max positions. */
  322.     EGLV_GetGadgetRect(object, gpr->gpr_GInfo, &rect);
  323.  
  324.     /* Calculate real dimensions. */
  325.     container.Left        =rect.MinX;
  326.     container.Top            =rect.MinY;
  327.     container.Width        =1+rect.MaxX-rect.MinX;
  328.     container.Height    =1+rect.MaxY-rect.MinY;
  329.  
  330.     dri=gpr->gpr_GInfo->gi_DrInfo;
  331.  
  332.     if(gad->Flags & GFLG_DISABLED)
  333.         State=IDS_DISABLED;
  334.     else if(gad->Flags & GFLG_SELECTED)
  335.         State=IDS_SELECTED;
  336.     else
  337.         State=IDS_NORMAL;
  338.  
  339.     /* Frame rendering goes here. */
  340.     SetAttrs(lv->FrameImage,
  341.                       IA_Left,    container.Left,
  342.                       IA_Top,     container.Top,
  343.                       IA_Width,   container.Width,
  344.                       IA_Height,  container.Height,
  345.                       TAG_END);
  346.  
  347.     DrawImageState(RP, lv->FrameImage, 0, 0, State, dri);
  348.  
  349.     if(dri)
  350.     {
  351.         TextPen        =dri->dri_Pens[TEXTPEN];
  352.         ImagePen1    =dri->dri_Pens[SHINEPEN];
  353.         ImagePen2    =dri->dri_Pens[SHADOWPEN];
  354.     }
  355.     else
  356.     {
  357.         // If for some unknown reason Drawinfo is NULL then we
  358.         // Use these predefined values, which should work atleast
  359.         // for current OS releases.
  360.         TextPen        =ImagePen2=1;
  361.         ImagePen1    =2;
  362.     }
  363.  
  364.     /*******************************/
  365.     /* Text rendering starts here. */
  366.     /*******************************/
  367.  
  368.     /* Do we have a proper font. If not we use the font we have in RastPort. */
  369.     if(lv->Font==NULL)
  370.         lv->Font=RP->Font;
  371.     else
  372.         SetFont(RP, lv->Font);
  373.  
  374. /*
  375.     /* Check if we have nothing to print. */
  376.     if(lv->Count>0)
  377.     {
  378.     ULONG len, i = 0;
  379.     char *label_name;
  380.  
  381.     node = lv->Labels->lh_Head;
  382.     while( node->ln_Succ ) {
  383.         if( i == lv->Active ) {
  384.             label_name = node->ln_Name;
  385.             if( label_name ) {
  386.                 len = TextFit( RP, label_name, (ULONG)strlen(label_name),
  387.                     &temp_te, NULL, 1, (ULONG)container.Width - 28,
  388.                     1LU + lv->Font->tf_YSize);
  389.  
  390.                 TextWidth = 1 + temp_te.te_Extent.MaxX - temp_te.te_Extent.MinX;
  391.  
  392.                 SetAPen(RP, TextPen);
  393.                 Move( RP, 10L + container.Left + (container.Width - TextWidth)/2
  394.                     - temp_te.te_Extent.MinX, (LONG)
  395.                     lv->Font->tf_Baseline + (1 + container.Top + rect.MaxY
  396.                     - lv->Font->tf_YSize)/2 );
  397.  
  398.                 Text( RP, label_name, len );
  399.             }
  400.  
  401.             /* End the drawing. */
  402.             break;
  403.         }
  404.         else {
  405.             i++;
  406.             node = node->ln_Succ;
  407.         }
  408.     }
  409.     }
  410. */
  411.  
  412.     /* Disabled pattern rendering is here. */
  413.     if(State==IDS_DISABLED)
  414.     {
  415.         BorderHeight=1;
  416.         BorderWidth    =(IntuitionBase->LibNode.lib_Version<39 ? 1 : 2);
  417.  
  418.         container.Left    +=BorderWidth;
  419.         container.Top        +=BorderHeight;
  420.         container.Width    =MAX(1, container.Width - 2*BorderWidth);
  421.         container.Height=MAX(1, container.Height-2*BorderHeight);
  422.  
  423.         SetDrMd(RP,JAM1);
  424.         SetAfPt(RP, patterndata, 1);
  425.  
  426.         RectFill(RP, (LONG)container.Left, (LONG)container.Top,
  427.                             -1L + container.Left + container.Width,
  428.                             -1L + container.Top + container.Height);
  429.  
  430.         SetAfPt(RP, NULL, 0 );
  431.     }
  432.  
  433.     /* Copy current Rectangle. */
  434.     lv->rect=rect;
  435.  
  436.     return retval;
  437. }
  438.  
  439. static ULONG EGLV_GOACTIVE(Class *class, Object *object, struct gpInput *gpi)
  440. {
  441.     ULONG retval = GMR_MEACTIVE, Left, Top;
  442.     struct RastPort *rp;
  443.     struct ListviewData *lv = INST_DATA( class, object );
  444.     struct GadgetInfo *gi = gpi->gpi_GInfo;
  445.     struct Gadget *gad = (struct Gadget *)object;
  446.  
  447.     if(gad->Flags & GFLG_DISABLED)
  448.         return(GMR_NOREUSE);
  449.  
  450.     /* Call first our parent class. */
  451.     (void)DoSuperMethodA(class, object, gpi);
  452.  
  453.     /* Chech whether we were activated from mouse or keyboard. */
  454.     lv->ActiveFromMouse=(gpi->gpi_IEvent != NULL);
  455.  
  456.     /* Select this gadget. */
  457.     gad->Flags|=GFLG_SELECTED;
  458.  
  459.     if(rp=ObtainGIRPort(gi))
  460.     {
  461.         /* Render ourselves as selected gadget. */
  462.         DoMethod(object, GM_RENDER, gi, rp, GREDRAW_UPDATE);
  463.         ReleaseGIRPort( rp );
  464.  
  465.         /* Get the domain top/left position. */
  466.         Left=gi->gi_Domain.Left;
  467.         Top    =gi->gi_Domain.Top;
  468.  
  469.         /* If this is window, we have to add window Left/Top values too. */
  470.     if(gi->gi_Window)
  471.         {
  472.             Left+=gi->gi_Window->LeftEdge;
  473.             Top    +=gi->gi_Window->TopEdge;
  474.         }
  475.  
  476.         /* Count how many items fits to menu. */
  477.         lv->FitsItems=(gi->gi_Screen->Height - 4) / lv->ItemHeight;
  478.         if(lv->FitsItems>lv->Count)
  479.             lv->FitsItems=lv->Count;
  480.  
  481.         lv->popup_window=OpenWindowTags(NULL,
  482.         WA_Left,            Left + lv->rect.MinX,
  483.         WA_Top,             Top + lv->rect.MaxY,
  484.         WA_Width,           1 + lv->rect.MaxX - lv->rect.MinX,
  485.         WA_Height,          4 + lv->FitsItems*lv->ItemHeight,
  486.         WA_Activate,        FALSE,
  487.         WA_CustomScreen,    gi->gi_Screen,
  488.         WA_SizeGadget,      FALSE,
  489.         WA_DragBar,         FALSE,
  490.         WA_DepthGadget,     FALSE,
  491.         WA_CloseGadget,     FALSE,
  492.         WA_Borderless,      TRUE,
  493.         WA_Flags,           0,
  494.         WA_AutoAdjust,      TRUE,
  495.         WA_RMBTrap,         TRUE,
  496.         WA_SimpleRefresh,   TRUE,
  497.         WA_NoCareRefresh,   TRUE,
  498.         TAG_END);
  499.  
  500.         if(lv->popup_window==NULL)
  501.             retval=GMR_NOREUSE;
  502.     else
  503.     {
  504.             /* We make sure Active item isn't too large to display. */
  505.             if(lv->FitsItems<lv->Active)
  506.                 lv->Active=lv->FitsItems-1;
  507.  
  508.             /* If activated from keyboard we can set temporary value
  509.             ** to currently activated item. Otherwise we set it
  510.             ** to -1 which means that there is no active item. */
  511.             lv->Temp_Active=(lv->ActiveFromMouse ? (ULONG)~0 : lv->Active);
  512.  
  513.             /* Render all items. */
  514.             EGLV_DrawPopupWindow( lv, gi->gi_DrInfo, 0, -1);
  515.         }
  516.     }
  517.     else
  518.         retval=GMR_NOREUSE;
  519.  
  520.     return retval;
  521. }
  522.  
  523. static ULONG EGLV_HANDLEINPUT(Class *class, Object *object, struct gpInput *gpi)
  524. {
  525.     ULONG retval = GMR_MEACTIVE;
  526.     struct InputEvent *ie = gpi->gpi_IEvent;
  527.     struct ListviewData *lv = INST_DATA(class, object);
  528.     WORD X, Y;
  529.     WORD count, old_active;
  530.     struct GadgetInfo *gi = gpi->gpi_GInfo;
  531.     struct TagItem tags;    /* If our possible child class, doesn't know
  532.                                                 ** how to handle NULL AttrList ptr, then
  533.                                                 ** this can save lots of crashes. */
  534.  
  535.     /* If there is anykind of AutoPoint program then our main window
  536.     ** might get inactive and we wouldn't get any more messages.
  537.     ** So we check out that we are active and deactivate ourselves
  538.     ** if our window isn't active anymore. */
  539.  
  540.     if(gi->gi_Window)
  541.         if((gi->gi_Window->Flags & WFLG_WINDOWACTIVE)==0)
  542.             return(GMR_NOREUSE);
  543.  
  544.     if(lv->ActiveFromMouse)
  545.     {
  546.         X=lv->popup_window->MouseX;
  547.         Y=lv->popup_window->MouseY;
  548.  
  549.         count=( (Y - 2) >= 0 ) ? (Y - 2) / (lv->ItemHeight) : ~0;
  550.  
  551.         old_active=lv->Temp_Active;
  552.  
  553.         if( (X > 2) && (X < (lv->popup_window->Width - 2))
  554.             && (count >= 0) && (count < lv->FitsItems) ) {
  555.         lv->Temp_Active = (UWORD)count;
  556.     }
  557.     else lv->Temp_Active = (UWORD)~0;
  558.  
  559.     if( old_active != (WORD)lv->Temp_Active ) {
  560.         EGLV_DrawPopupWindow( lv, gi->gi_DrInfo,(ULONG)lv->Temp_Active, 1 );
  561.         EGLV_DrawPopupWindow( lv, gi->gi_DrInfo,(ULONG)old_active, 1 );
  562.     }
  563.  
  564.     while( ie && (retval == GMR_MEACTIVE) ) {
  565.         if( ie->ie_Class == IECLASS_RAWMOUSE ) {
  566.             if( ie->ie_Code == SELECTUP ) {
  567.                 retval = GMR_NOREUSE;
  568.  
  569.                 if( (lv->Temp_Active != (UWORD)~0) ) {
  570.                     lv->Active = lv->Temp_Active;
  571.                     EGLV_MakeCheckings( lv );
  572.  
  573.                     EGLV_SetTagArg(tags, TAG_END, NULL);
  574.                     (VOID)DoMethod( object, OM_NOTIFY, &tags, gi, 0);
  575.  
  576.                     retval |= GMR_VERIFY;
  577.                     *gpi->gpi_Termination = (ULONG)lv->Active;
  578.                 }
  579.             }
  580.         }
  581.  
  582.         ie = ie->ie_NextEvent;
  583.     }
  584. }
  585. else {
  586.     while( ie && (retval == GMR_MEACTIVE) ) {
  587.         switch( ie->ie_Class )
  588.         {
  589.         case IECLASS_RAWMOUSE:
  590.             if( ie->ie_Code != IECODE_NOBUTTON ) {
  591.                 retval = GMR_REUSE; /* Reuse the InputEvent. */
  592.             }
  593.             break;
  594.         case IECLASS_RAWKEY:
  595.             old_active = lv->Temp_Active;
  596.             switch( ie->ie_Code )
  597.             {
  598.             case CURSORDOWN:
  599.                 if( ie->ie_Qualifier & (ALTLEFT|ALTRIGHT) ) {
  600.                     lv->Temp_Active = lv->FitsItems-1;  /* Jump to end. */
  601.                 }
  602.                 else if( lv->Temp_Active < (lv->FitsItems-1) ) {
  603.                     lv->Temp_Active += 1;
  604.                 }
  605.                 break;
  606.             case CURSORUP:
  607.                 if( ie->ie_Qualifier & (ALTLEFT|ALTRIGHT) ) {
  608.                     lv->Temp_Active = 0;    /* Jump to start. */
  609.                 }
  610.                 else if( lv->Temp_Active > 0 ) {
  611.                     lv->Temp_Active -= 1;
  612.                 }
  613.                 break;
  614.             case 0x45:  /* ESC key. */
  615.                 retval = GMR_NOREUSE;
  616.                 break;
  617.             case 0x44:  /* RETURN key. */
  618.                 lv->Active = lv->Temp_Active;
  619.                 EGLV_MakeCheckings( lv );
  620.  
  621.                 EGLV_SetTagArg(tags, TAG_END, NULL);
  622.                 (VOID)DoMethod( object, OM_NOTIFY, &tags, gi, 0);
  623.  
  624.                 retval = GMR_NOREUSE|GMR_VERIFY;
  625.                 *gpi->gpi_Termination = (ULONG)lv->Active;
  626.                 break;
  627.             }
  628.  
  629.             /* Update the popupwindow items, if changes were made. */
  630.             if( old_active != lv->Temp_Active ) {
  631.                 EGLV_DrawPopupWindow( lv, gi->gi_DrInfo,
  632.                     (ULONG)lv->Temp_Active, 1 );
  633.                 EGLV_DrawPopupWindow( lv, gi->gi_DrInfo,
  634.                     (ULONG)old_active, 1 );
  635.             }
  636.         }
  637.  
  638.         ie = ie->ie_NextEvent;
  639.     }
  640. }
  641.  
  642. return(retval);
  643. }
  644.  
  645. static ULONG EGLV_GOINACTIVE( Class *class,
  646.                               Object *object,
  647.                               struct gpGoInactive *gpgi )
  648. {
  649.     ULONG retval;
  650.     struct RastPort *rp;
  651.     struct ListviewData *lv = INST_DATA(class, object);
  652.  
  653.     retval = DoSuperMethodA(class, object, gpgi);
  654.  
  655.     ((struct Gadget *)object)->Flags &= ~GFLG_SELECTED;
  656.  
  657.     rp = ObtainGIRPort( gpgi->gpgi_GInfo );
  658.     if( rp ) {
  659.         DoMethod( object, GM_RENDER, gpgi->gpgi_GInfo, rp, GREDRAW_UPDATE );
  660.         ReleaseGIRPort( rp );
  661.     }
  662.  
  663.     if( lv->popup_window ) {
  664.         CloseWindow(lv->popup_window);
  665.         lv->popup_window = NULL;
  666.     }
  667.  
  668.     return(retval);
  669. }
  670.  
  671. /* Static functions for help with real Method functions. */
  672.  
  673. static void EGLV_MakeCheckings( struct ListviewData *lv )
  674. {
  675.     struct Node *node;
  676.  
  677.     lv->Count = 0;
  678.  
  679.     if( lv->Labels == NULL ) {
  680.         lv->Active = 0;
  681.     }
  682.     else if( lv->Labels != (struct List *)~0 ) {
  683.         node = (struct Node *)lv->Labels->lh_Head;
  684.         while( node->ln_Succ ) {
  685.             lv->Count += 1;
  686.             node = node->ln_Succ;
  687.         }
  688.  
  689.         if( lv->Active >= lv->Count ) {
  690.             lv->Active = lv->Count + (lv->Count == 0) - 1;
  691.         }
  692.     }
  693. }
  694.  
  695. static void EGLV_GetGadgetRect( Object *object,
  696.                                 struct GadgetInfo *gi,
  697.                                 struct Rectangle *rect )
  698. {
  699.     struct Gadget *gad = (struct Gadget *)object;
  700.     LONG W, H;
  701.  
  702.     rect->MinX = gad->LeftEdge;
  703.     rect->MinY = gad->TopEdge;
  704.     W = gad->Width;
  705.     H = gad->Height;
  706.  
  707.     if( gi ) {
  708.         if( gad->Flags & GFLG_RELRIGHT ) rect->MinX += gi->gi_Domain.Width - 1;
  709.         if( gad->Flags & GFLG_RELBOTTOM ) rect->MinY += gi->gi_Domain.Height - 1;
  710.         if( gad->Flags & GFLG_RELWIDTH ) W += gi->gi_Domain.Width;
  711.         if( gad->Flags & GFLG_RELHEIGHT ) H += gi->gi_Domain.Height;
  712.     }
  713.  
  714.     rect->MaxX = rect->MinX + W - (W > 0);
  715.     rect->MaxY = rect->MinY + H - (H > 0);
  716. }
  717.  
  718. static void EGLV_DrawPopupWindow( struct ListviewData *lv,
  719.                                   struct DrawInfo *dri,
  720.                                   ULONG From, LONG Count)
  721. {
  722.     int i, End;
  723.     struct Node *node;
  724.     struct Window *win = lv->popup_window;
  725.     struct RastPort *RP = win->RPort;
  726.  
  727.     if( lv->Count && dri ) {
  728.         /* If we want to draw all entries then we draw
  729.         ** window borders too. */
  730.         if( Count == -1) {
  731.             Count = lv->FitsItems;
  732.  
  733.             if( lv->NewLook ) {
  734.                 /* Set background to MENU background color. */
  735.                 SetRast( RP, (ULONG)dri->dri_Pens[BARBLOCKPEN] );
  736.  
  737.                 SetAPen( RP, (ULONG)dri->dri_Pens[BARDETAILPEN] );
  738.                 Move( RP, 0, -1L + win->Height );
  739.                 Draw( RP, 0, 0 );
  740.                 Draw( RP, -1L + win->Width, 0 );
  741.                 Draw( RP, -1L + win->Width, -1L + win->Height);
  742.                 Draw( RP, 1, -1L + win->Height);
  743.                 Draw( RP, 1, 1);
  744.                 Move( RP, -2L + win->Width, 1 );
  745.                 Draw( RP, -2L + win->Width, -2L + win->Height);
  746.             }
  747.             else {
  748.                 SetAPen( RP, (ULONG)dri->dri_Pens[SHINEPEN]);
  749.                 Move( RP, 0, -1L + win->Height);
  750.                 Draw( RP, 0, 0 );
  751.                 Draw( RP, -1L + win->Width, 0 );
  752.                 SetAPen( RP, (ULONG)dri->dri_Pens[SHADOWPEN]);
  753.                 Draw( RP, -1L + win->Width, -1L + win->Height);
  754.                 Draw( RP, 1, -1L + win->Height);
  755.             }
  756.         }
  757.  
  758.         SetFont( RP, lv->Font );
  759.         SetDrMd( RP, JAM1);
  760.  
  761.         node = lv->Labels->lh_Head;
  762.  
  763.         for( i = 0, End = From + Count; node->ln_Succ ; i++ ) {
  764.             if( i < lv->FitsItems ) {
  765.                 if( (i >= From) && ( i < End ) ) {
  766.                     EGLV_DrawFrame( lv->popup_window, i, dri, node->ln_Name,
  767.                         lv->Font, (BOOL)(i == lv->Temp_Active),
  768.                         lv->NewLook, (ULONG)lv->ItemHeight );
  769.                 }
  770.                 else if( i >= End ) return;
  771.             }
  772.  
  773.             node = node->ln_Succ;
  774.         }
  775.     }
  776. }
  777.  
  778. static void EGLV_DrawFrame( struct Window *win,
  779.                             int order,
  780.                             struct DrawInfo *dri,
  781.                             UBYTE *name,
  782.                             struct TextFont *tf,
  783.                             BOOL Active,
  784.                             BOOL NewLook,
  785.                             ULONG ItemHeight )
  786. {
  787.     ULONG   Pen1, Pen2, TextPen, BPen;
  788.     ULONG   Top, Width, Bottom, MaxX,
  789.             Len, TextWidth,
  790.             font_height = tf->tf_YSize;
  791.     struct  RastPort *RP = win->RPort;
  792.     struct  TextExtent temp_te;
  793.  
  794.     TextPen = dri->dri_Pens[TEXTPEN];
  795.  
  796.     if( Active ) {
  797.         if( NewLook ) {
  798.             BPen = dri->dri_Pens[BARDETAILPEN];
  799.             TextPen = dri->dri_Pens[BARBLOCKPEN];   /* Override previous value. */
  800.         }
  801.         else {
  802.             Pen2 = dri->dri_Pens[SHINEPEN];
  803.             Pen1 = dri->dri_Pens[SHADOWPEN];
  804.             BPen = dri->dri_Pens[FILLPEN];
  805.         }
  806.     }
  807.     else {
  808.         if( NewLook ) {
  809.             BPen = dri->dri_Pens[BARBLOCKPEN];
  810.             TextPen = dri->dri_Pens[BARDETAILPEN];  /* Override previous value. */
  811.         }
  812.         else {
  813.             Pen2 = dri->dri_Pens[SHADOWPEN];
  814.             Pen1 = dri->dri_Pens[SHINEPEN];
  815.             BPen = dri->dri_Pens[BACKGROUNDPEN];
  816.         }
  817.     }
  818.  
  819.     Top = 2 + order * ItemHeight;
  820.     Bottom = Top + ItemHeight - 1;
  821.     MaxX = win->Width - 4;
  822.  
  823.     SetAPen( RP, BPen );
  824.     RectFill( RP, 4, Top, MaxX - 1, Bottom );
  825.  
  826.     if( NewLook == FALSE ) {    /* Draw Recessed Border. */
  827.         SetAPen( RP, Pen1);
  828.         Move( RP, 3, Bottom);
  829.         Draw( RP, 3, Top );
  830.         Draw( RP, MaxX, Top );
  831.         SetAPen( RP, Pen2);
  832.         Draw( RP, MaxX, Bottom );
  833.         Draw( RP, 4, Bottom );
  834.     }
  835.  
  836.     SetAPen( RP, TextPen);
  837.  
  838.     Width = win->Width - 10;
  839.  
  840.     Len = TextFit( RP, name, (ULONG)strlen(name), &temp_te, NULL, 1,
  841.         Width, 1 + font_height);
  842.  
  843.     TextWidth = temp_te.te_Extent.MaxX - temp_te.te_Extent.MinX;
  844.  
  845.     Move( RP, 5 + (Width - TextWidth)/2 - temp_te.te_Extent.MinX,
  846.         (ItemHeight - font_height)/2 + 1 + Top + tf->tf_Baseline );
  847.     Text( RP, name, Len );
  848. }
  849.  
  850. #endif
  851.